# -*- coding: utf-8 -*-
"""
Compute best/worst-case outcomes for 6/49 draws against a list of 3-number bets.
- Best by payout (120*x_3of3 + 19*x_3of2) and best by exact-3 hits.
- Worst by total winners (minimize x_3of3 + x_3of2).
Usage:
    python lotto_best_worst_analysis.py 香港1.txt 香港2.txt 香港3.txt 香港4.txt
"""
import sys, re
from collections import Counter
from itertools import combinations

def parse_three_numbers(line: str):
    nums = re.findall(r"\d+", line)
    if len(nums) < 4:
        return None
    a,b,c = map(int, nums[-3:])
    return tuple(sorted((a,b,c)))

def to_mask(nums):
    m = 0
    for x in nums:
        m |= 1 << (x-1)
    return m

def eval_counts(S_mask, triple_masks):
    k33 = 0
    k32 = 0
    for m, cnt in triple_masks:
        matches = (m & S_mask).bit_count()
        if matches == 3:
            k33 += cnt
        elif matches == 2:
            k32 += cnt
    total = k33 + k32
    payout = 120*k33 + 19*k32
    return k33, k32, total, payout

def mask_to_nums(S_mask):
    return [i+1 for i in range(49) if (S_mask >> i) & 1]

def top_candidates(single_freq, kN=16):
    cands = set()
    top = [n for n,_ in single_freq.most_common(kN)]
    bot = [n for n,_ in sorted(single_freq.items(), key=lambda kv: (kv[1], kv[0]))[:kN]]
    for pool in (top, bot, list(dict.fromkeys(top[:8]+bot[:8]))):
        for nums in combinations(pool, 6):
            cands.add(to_mask(nums))
    cands.add(to_mask([n for n,_ in single_freq.most_common(6)]))
    return cands

def improve_local(S_mask, triple_masks, objective="payout", minimize=False, max_iters=100):
    def score(m):
        k33,k32,total,pay = eval_counts(m, triple_masks)
        if objective == "payout":
            return (pay, k33, k32) if not minimize else (-total, -k33, -pay)
        else:
            return (k33, k32, pay) if not minimize else (-k33, -total, -k32)
    best = S_mask
    best_score = score(best)
    for _ in range(max_iters):
        improved = False
        S_nums = set(mask_to_nums(best))
        not_in = set(range(1,50)) - S_nums
        for out in list(S_nums):
            for inn in list(not_in):
                m2 = best ^ (1 << (out-1)) ^ (1 << (inn-1))
                sc = score(m2)
                if sc > best_score:
                    best, best_score = m2, sc
                    improved = True
                    break
            if improved: break
        if not improved: break
    return best

def main(paths):
    triples = []
    for fp in paths:
        with open(fp, "r", encoding="utf-8", errors="ignore") as f:
            for i, line in enumerate(f):
                if i == 0 or not line.strip(): continue
                t = parse_three_numbers(line)
                if t: triples.append(t)

    unique_triples = Counter(triples)
    triple_masks = [(to_mask(t), cnt) for t,cnt in unique_triples.items()]

    # single frequencies
    single_freq = Counter()
    for m,cnt in triple_masks:
        b = m
        while b:
            lsb = b & -b
            idx = (lsb.bit_length()-1)
            single_freq[idx+1] += cnt
            b ^= lsb

    cands = top_candidates(single_freq, kN=16)

    # Best by payout
    best_pay = max(cands, key=lambda m: eval_counts(m, triple_masks)[3])
    best_pay = improve_local(best_pay, triple_masks, objective="payout", minimize=False)
    # Best by k33
    best_k33 = max(cands, key=lambda m: (eval_counts(m, triple_masks)[0], eval_counts(m, triple_masks)[3]))
    best_k33 = improve_local(best_k33, triple_masks, objective="k33", minimize=False)
    # Worst by total
    worst_total = min(cands, key=lambda m: eval_counts(m, triple_masks)[2])
    worst_total = improve_local(worst_total, triple_masks, objective="payout", minimize=True)

    def pack(name, m):
        k33,k32,total,pay = eval_counts(m, triple_masks)
        return {
            "方案": name,
            "开奖号码": mask_to_nums(m),
            "3中3个数": k33,
            "3中2个数": k32,
            "总中奖注数(≥2中)": total,
            "总赔率收益(120*3中3 + 19*3中2)": pay
        }

    print("总注数:", sum(unique_triples.values()))
    print(pack("最优总收益", best_pay))
    print(pack("最优3中3数量", best_k33))
    print(pack("最差（最少中奖数）", worst_total))

if __name__ == "__main__":
    if len(sys.argv) < 2:
        paths = ["香港1.txt", "香港2.txt", "香港3.txt", "香港4.txt"]
    else:
        paths = sys.argv[1:]
    main(paths)
